/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       creature_detail_display.h

	$Header: /game/creature_detail_display.h $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "creature_detail_display.h"

#include "bitmap_group.h"
#include "bitmap_group_cache.h"
#include "bitmap_group_window.h"
#include "creature.h"
#include "creature_ability_properties.h"
#include "creature_array_window.h"
#include "creature_traits.h"
#include "enum_operations.h"
#include "external_string.h"
#include "format_string.h"
#include "get_artifact_damage_modifier.h"
#include "hero.h"
#include "hero_class_properties.h"
#include "luck_icon_window.h"
#include "morale_icon_window.h"
#include "replace_keywords.h"
#include "skill.h"
#include "skill_icon.h"
#include "skill_properties.h"
#include "standard_fonts.h"
#include "text_window.h"

extern t_external_string const k_text_hero_level( "hero_level.dialog" );
extern t_external_string const k_text_hit_points;
extern t_external_string const k_text_spell_points;
extern t_external_string const k_text_damage;
extern t_external_string const k_text_movement( "movement.dialog" );

// --------------------------------------------------------------------
// utility object to display information about a selected creature 
// --------------------------------------------------------------------
void t_creature_detail_display::create( t_bitmap_group_ptr bitmaps, t_window* text_parent, t_screen_point text_origin,
									    t_window* icon_parent, t_screen_point icon_origin )
{
	// add health

	m_bitmaps = bitmaps;
	m_text_parent = text_parent;
	m_text_origin = text_origin;
	m_is_boat = false;
	m_creature_name = create_text( "creature_name", "" );
	m_hero_class = create_text( "hero_class", "" );
	m_creature_health = create_text( "creature_health", "health_text", k_text_hit_points );
	m_creature_damage = create_text( "creature_damage", "damage_text", k_text_damage );
	m_creature_move = create_text( "creature_move", "move_text", k_text_movement, 12 );
	m_creature_mana = create_text( "creature_mana", "mana_text", k_text_spell_points, 12 );

	// add morale
	t_bitmap_layer const* layer;
	t_screen_point		  point;

	layer = bitmaps->find( "morale" );
	if (layer == 0)
		m_creature_morale = 0;
	else
	{
		m_creature_morale = new t_morale_icon_window( layer->get_rect() - text_origin,
			                                          text_parent );
		m_creature_morale->set_visible( false );
	}
	layer = bitmaps->find( "luck" );
	if (layer == 0)
		m_creature_luck = 0;
	else
	{
		m_creature_luck = new t_luck_icon_window( layer->get_rect() - text_origin, 
			                                      text_parent );
		m_creature_luck->set_visible( false );
	}

	// create skill icons
	int i;

	for (i = 0; i < k_skill_icon_count; i++)
	{
		layer = bitmaps->find( format_string( "creature_skill_%i", i + 1 ) );
		if (layer == 0)
			m_creature_skills[i] = 0;
		else
			m_creature_skills[i] = new t_skill_icon( t_skill(), 
										layer->get_rect() - icon_origin, icon_parent );
	}

	// create skill frame
	t_window* window;

	layer = bitmaps->find( "creature icon holders" );
	if (layer != 0)
	{
		window = new t_bitmap_layer_window( layer, -icon_origin, icon_parent );
	}
}

// --------------------------------------------------------------------
// utility object to display information about a selected creature 
// --------------------------------------------------------------------

void t_creature_detail_display::select_creature( t_creature_array_window* window, int index )
{
	t_creature_array* army = window->get_army();

	if (index < 0)
		army = 0;
	if (army != 0 && (*army)[index].get_number() == 0)
		army = 0;

	// show/hide windows
	if (m_creature_name == 0)
		return;

	m_creature_name->set_visible( army != 0 );
	m_hero_class->set_visible( army != 0 );
	m_creature_health->set_visible( army != 0 );
	m_creature_health->set_center_horizontal();
	m_creature_damage->set_visible( army != 0 );
	m_creature_damage->set_center_horizontal();
	m_creature_move->set_visible( army != 0 );
	m_creature_move->set_center_horizontal();
	m_creature_mana->set_visible( army != 0 );
	m_creature_mana->set_center_horizontal();
	m_creature_luck->set_visible( army != 0 );
	m_creature_morale->set_visible( army != 0 );
	if (army == 0)
	{
		int i;

		for (i = 0; i < k_skill_icon_count; i++)
			m_creature_skills[i]->set_skill( t_skill() );
		return;
	}

	t_creature_stack const& stack = (*army)[index];
	t_hero const*           hero = stack.get_hero();

	m_hero_class->set_visible( hero != 0 );
	if (hero == 0)
	{
		m_creature_name->set_text( format_string( "%i %s", stack.get_number(),
		                           stack.get_name().c_str() ) );
		m_creature_name->set_right_click_text( get_traits( stack.get_creature_type() ).help_text );
		set_skills( *stack.get_creature() );
	}
	else
	{
		std::string text;

		text = replace_keywords( k_text_hero_level, "%level", format_string( "%i", hero->get_level() ),
			                     "%class_name", hero->get_class_name() );
		m_hero_class->set_text( text );
		m_hero_class->set_right_click_text( hero->get_class_description() );
		m_creature_name->set_text( stack.get_name() );
		set_skills( *hero );
	}

	bool ranged = stack.has_ability( k_ability_ranged );
	int  artifact_damage = get_artifact_damage( stack, ranged );
	int  damage_low = stack.get_damage_low() + artifact_damage;
	int  damage_high = stack.get_damage_high() + artifact_damage;

	m_creature_health->set_text( format_string( "%i", stack.get_hit_points() ) );
	m_creature_damage->set_text( format_string( "%i-%i", damage_low, damage_high ));

	int maximum  = army->get_max_movement( stack ) / 100;
	int movement = army->get_movement( stack ) / 100;

	m_creature_move->set_text( format_string( "%i / %i", movement, maximum ) );
	m_creature_mana->set_text( format_string( "%i / %i", stack.get_spell_points(),
										      stack.get_maximum_spell_points() ) );

	m_creature_morale->set_creature( &stack, army );
	m_creature_morale->update();
	m_creature_luck->set_creature( &stack );
	m_creature_luck->update();
}

// --------------------------------------------------------------------
// utility object to display information about a selected creature 
// --------------------------------------------------------------------
t_text_window* t_creature_detail_display::create_text( std::string layer_name, std::string text, int font_size )
{
	t_bitmap_layer const*	layer;
	t_text_window*			window;
	t_screen_rect			rect;

	layer = m_bitmaps->find( layer_name );
	if (layer == 0)
		return 0;

	rect = layer->get_rect() - m_text_origin;
    int font_height;

    if (font_size)
        font_height = font_size;
    else
        font_height = rect.height();

	window = new t_text_window( get_font( font_height ), rect, m_text_parent, text,
	                                  t_pixel_24(0,0,0) );
	window->set_drop_shadow( true, t_pixel_24(200,200,200) );
	return window;
}

// --------------------------------------------------------------------
// utility object to display information about a selected creature 
// --------------------------------------------------------------------
t_text_window* t_creature_detail_display::create_text( std::string text_layer, std::string label_layer,
							                           std::string label, int font_size )
{
	t_text_window* label_window;
	t_text_window* result;

	result = create_text( text_layer, "", font_size );
	if (result != 0)
		result->set_right_justified();
	label_window = create_text( label_layer, label, font_size );
	return result;
}

// --------------------------------------------------------------------
// utility object to display information about a selected creature 
// --------------------------------------------------------------------
void t_creature_detail_display::set_skills( t_creature const& creature )
{
	int i;
	t_creature_traits const& traits = get_traits( creature.get_creature_type() );

	for (i = 0; i < traits.abilities.size(); i++)
		m_creature_skills[i]->set_ability( traits.abilities[i] );
	while ( i < k_skill_icon_count)
	{
		m_creature_skills[i]->set_skill( t_skill() );
		i++;
	}
}

namespace
{
	class t_sort_by_primary
	{
	public:
		t_sort_by_primary( int const* primary_weight )
		{
			m_primary_weight = primary_weight;
		}
		bool operator()( t_skill const& left, t_skill const& right ) const
		{
			t_skill_type left_primary = get_primary_skill( left.skill );
			t_skill_type right_primary = get_primary_skill( right.skill );

			if (left_primary == right_primary)
				return left.skill < right.skill;
			if (m_primary_weight[left_primary] != m_primary_weight[right_primary])
				return m_primary_weight[left_primary] > m_primary_weight[right_primary];
			return left_primary < right_primary;
		}
	protected:
		int const* m_primary_weight;
	};
};

// --------------------------------------------------------------------
// utility object to display information about a selected creature 
// --------------------------------------------------------------------
void t_creature_detail_display::set_skills( t_hero const& hero )
{
	int					 i;
	int                  limit;
	t_skill_type		 skill_type;
	t_skill_type		 primary;
	t_skill_mastery		 mastery;
	int					 primary_weight[k_skill_primary_count];
	std::vector<t_skill> skills;

	// compute how many total levels are in each primary skill.
	memset( primary_weight, 0, sizeof( primary_weight ));
	for (skill_type = t_skill_type(0); skill_type < k_skill_count; enum_incr( skill_type ))
	{
		mastery = hero.get_skill( skill_type );
		if (mastery == k_mastery_none)
			continue;
		skills.push_back( t_skill( skill_type, mastery ) );
		primary = get_primary_skill( skill_type );
		primary_weight[primary] += mastery + 1;
	}
	std::sort( skills.begin(), skills.end(), t_sort_by_primary(primary_weight) );

	// set icons based on sorted list.
	limit = skills.size();
	if (limit > k_skill_icon_count)
		limit = k_skill_icon_count;
	for (i = 0; i < limit; i++)
		m_creature_skills[i]->set_skill( skills[i] );

	for (; i < k_skill_icon_count; i++)
		m_creature_skills[i]->set_skill( t_skill() );
}
